package bsf.http.pool;

import bsf.base.BsfException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.pool.PoolStats;

import java.util.concurrent.TimeUnit;

/**
 * Created by chejiangyi on 2017/3/31.
 * 默认的连接池实现,未来需要改进
 */
public class HttpClientPool implements AutoCloseable {

    private HttpClientConfig config = null;
    private  PoolingHttpClientConnectionManager poolingClientConnectionManager;
    // 5秒超时
    private RequestConfig requestConfig =null;
    //上次连接池回收时间
    private long lastRecoverConnectTime=System.currentTimeMillis();
    //上次检查连接池状态时间
    private long lastCheckPoolStateTime = System.currentTimeMillis();

    public HttpClientPool(HttpClientConfig config) {
        config = new HttpClientConfig();
        requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(config.ConnectionRequestTimeout)//请求超时时间
                .setSocketTimeout(config.SocketTimeout)//socket超时时间
                .setConnectTimeout(config.ConnectTimeout)//连接超时时间
                //.setCookieSpec("easy")
                .setRedirectsEnabled(config.RedirectsEnabled)
                .build();
        poolingClientConnectionManager = new PoolingHttpClientConnectionManager();
        poolingClientConnectionManager.setDefaultMaxPerRoute(config.DefaultMaxPerRoute);
        poolingClientConnectionManager.setMaxTotal(config.DefaultMaxTotal);

    }

    public CloseableHttpClient getClient()
    {
        if((lastCheckPoolStateTime-System.currentTimeMillis()>1000*5))//超过5s检测一次连接池状态
        {
            try {
                PoolStats poolStats = poolingClientConnectionManager.getTotalStats();
                int leased = poolStats.getLeased();
                int max = poolStats.getMax();
                int pending = poolStats.getPending();
                int available = poolStats.getAvailable();
                if (leased == max && pending > 0 && available == 0)
                    throw new BsfException("当前Http连接池被耗尽",this.getClass());
                if (pending > config.MaxPendingConnect)
                    throw new BsfException("当前等待连接数超过" + config.MaxPendingConnect,this.getClass());
            }
            finally {
                lastCheckPoolStateTime = System.currentTimeMillis();
            }
        }
        if((lastRecoverConnectTime-System.currentTimeMillis())>1000*60*2)//超过2分钟回收一次连接池
        {
            try {
                poolingClientConnectionManager.closeExpiredConnections();
                poolingClientConnectionManager.closeIdleConnections(30, TimeUnit.SECONDS);
            }catch (Exception e){}
            lastRecoverConnectTime = System.currentTimeMillis();
        }
        return  HttpClients.custom().setConnectionManager(poolingClientConnectionManager).setDefaultRequestConfig(requestConfig).build();
    }

    public void close()
    {
        if(poolingClientConnectionManager!=null)
            poolingClientConnectionManager.close();
        config=null;
        requestConfig=null;
    }
}
